package com.hruiworks.campusgroup.utils;

import com.hruiworks.campusgroup.enums.ErrorCode;
import com.hruiworks.campusgroup.exception.BusinessException;
import com.hruiworks.campusgroup.functional.IntegerGetter;
import com.hruiworks.campusgroup.functional.StringGetter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.BooleanUtils;
import org.redisson.api.RedissonClient;
import org.springframework.data.redis.connection.BitFieldSubCommands;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

@Slf4j
public class RedisUtils {


    private static RedissonClient redissonClient;

    private static RedisTemplate<String, Object> redisTemplate;


    private static void init() {
        redissonClient = SpringContextUtils.getBean(RedissonClient.class);
        redisTemplate = SpringContextUtils.getBean("redisTemplate", RedisTemplate.class);
    }

    private static void initJudge() {
        if (Objects.isNull(redisTemplate)) {
            init();
            if (Objects.isNull(redisTemplate)) {
                log.info("redisTemplate初始化失败");
                throw new BusinessException(ErrorCode.OTHER_ERROR, "redis出错");
            }
        }
    }


    /**
     * 设置位图值
     *
     * @param key    键
     * @param offset 偏移量
     * @param flag   0 or 1
     * @return 插入结果
     */
    public static Boolean setBit(String key, long offset, boolean flag) {
        initJudge();
        return redisTemplate.opsForValue().setBit(key, offset, flag);
    }

    /**
     * 获取bit
     * @param key
     * @param offset
     */
    public static Boolean getBit(String key, long offset) {
        return redisTemplate.opsForValue().getBit(key, offset);
    }

    /**
     * key是否存在
     * @param key
     * @return true存在，false不存在
     */
    public static Boolean keyExists(String key) {
        return redisTemplate.opsForValue().getOperations().hasKey(key);
    }

    /**
     * 获取位图的1数量
     *
     * @param key
     * @return
     */
    public static Long bitCount(String key) {
        initJudge();
        return redisTemplate.execute((RedisCallback<Long>) con -> con.bitCount(key.getBytes()));
    }


    /**
     * 批量设置bitmap
     *
     * @param key
     * @param offsetList
     * @param flag
     * @return
     */
    public static List<Long> bitFieldSet(String key, List<Long> offsetList, boolean flag) {
        initJudge();
        int bit = 0;
        if (BooleanUtils.isTrue(flag)) {
            bit = 1;
        }
        BitFieldSubCommands.BitFieldSubCommand[] list = new BitFieldSubCommands.BitFieldSubCommand[offsetList.size()];
        for (int i = 0; i < list.length; i++) {
            BitFieldSubCommands.BitFieldSet bitFieldSet = BitFieldSubCommands.BitFieldSet.create(BitFieldSubCommands.BitFieldType.unsigned(1),
                    BitFieldSubCommands.Offset.offset(offsetList.get(i)), bit);
            list[i] = bitFieldSet;
        }

        BitFieldSubCommands fieldSubCommands = BitFieldSubCommands.create(list);
        return redisTemplate.opsForValue().bitField(key, fieldSubCommands);

    }

    /**
     * 批量设置hashset
     * @param key 键
     * @param objectList 对象列表
     * @param fieldGetter 域getter
     * @param valueGetter 值getter
     * @param <T>
     */
    public static <T> void hashSet(String key, List<T> objectList, StringGetter<T> fieldGetter, IntegerGetter<T> valueGetter) {
        initJudge();
        HashMap<String, Integer> hashMap = new HashMap<>();
        objectList.forEach(t -> {
            String field = fieldGetter.get(t);
            Integer value = valueGetter.get(t);
            hashMap.put(field, value);
        });

        redisTemplate.opsForHash().putAll(key, hashMap);
    }

    public static void hashSet(String key, Map<String, Integer> hashMap ) {
        initJudge();

        redisTemplate.opsForHash().putAll(key, hashMap);
    }

    public static void hashDel(String key) {
        initJudge();

        redisTemplate.opsForHash().delete(key);
    }

    /**
     * hashGet
     * @param key
     * @param field
     */
    public static Object hashGet(String key, String field) {
        initJudge();
        Object value = redisTemplate.opsForHash().get(key, field);
        return value;
    }

    /**
     * hash自增
     * @param key
     * @param field
     * @param delta
     */
    public static void hashIncrBy(String key, String field, Long delta) {
        initJudge();
        redisTemplate.opsForHash().increment(key, field, delta);
    }
}